import {ColorSeries} from '../types/color';

export class ColorUtil {
  /**
   * 将十六进制颜色转换为RGB格式
   * @param hex 十六进制颜色字符串 (#RRGGBB 或 #RGB)
   * @returns RGB颜色对象 {r, g, b}
   * @example
   * ColorUtil.hexToRgb('#FF0000') // 返回 {r: 255, g: 0, b: 0}
   * ColorUtil.hexToRgb('#F00')    // 返回 {r: 255, g: 0, b: 0}
   */
  public static hexToRgb(hex: string): { r: number, g: number, b: number } | null {
    // 确保hex是有效的十六进制颜色字符串
    hex = hex.trim();
    if (!hex.startsWith('#')) {
      hex = '#' + hex;
    }

    // 移除#号
    hex = hex.replace('#', '');

    // 处理简写形式 (#RGB)
    if (hex.length === 3) {
      hex = hex.split('').map(char => char + char).join('');
    }

    if (hex.length !== 6) {
      return null;
    }

    const r = parseInt(hex.substring(0, 2), 16);
    const g = parseInt(hex.substring(2, 4), 16);
    const b = parseInt(hex.substring(4, 6), 16);

    if (isNaN(r) || isNaN(g) || isNaN(b)) {
      return null;
    }

    return {r, g, b};
  }

  /**
   * 将RGB颜色转换为十六进制格式
   * @param r 红色通道值 (0-255)
   * @param g 绿色通道值 (0-255)
   * @param b 蓝色通道值 (0-255)
   * @returns 十六进制颜色字符串
   * @example
   * ColorUtil.rgbToHex(255, 0, 0) // 返回 '#ff0000'
   */
  public static rgbToHex(r: number, g: number, b: number): string {
    return '#' + [r, g, b]
      .map(val => {
        const hex = Math.max(0, Math.min(255, Math.round(val))).toString(16);
        return hex.length === 1 ? '0' + hex : hex;
      })
      .join('');
  }

  /**
   * 将RGB颜色转换为HSL格式
   * @param r 红色通道值 (0-255)
   * @param g 绿色通道值 (0-255)
   * @param b 蓝色通道值 (0-255)
   * @returns HSL颜色对象 {h, s, l}，h范围0-360，s和l范围0-100
   * @example
   * ColorUtil.rgbToHsl(255, 0, 0) // 返回 {h: 0, s: 100, l: 50}
   */
  public static rgbToHsl(r: number, g: number, b: number): { h: number, s: number, l: number } {
    r /= 255;
    g /= 255;
    b /= 255;

    const max = Math.max(r, g, b);
    const min = Math.min(r, g, b);
    let h = 0, s = 0, l = (max + min) / 2;

    if (max !== min) {
      const d = max - min;
      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

      switch (max) {
        case r:
          h = (g - b) / d + (g < b ? 6 : 0);
          break;
        case g:
          h = (b - r) / d + 2;
          break;
        case b:
          h = (r - g) / d + 4;
          break;
      }

      h /= 6;
    }

    return {
      h: Math.round(h * 360),
      s: Math.round(s * 100),
      l: Math.round(l * 100)
    };
  }

  /**
   * 将HSL颜色转换为RGB格式
   * @param h 色相 (0-360)
   * @param s 饱和度 (0-100)
   * @param l 亮度 (0-100)
   * @returns RGB颜色对象 {r, g, b}
   * @example
   * ColorUtil.hslToRgb(0, 100, 50) // 返回 {r: 255, g: 0, b: 0}
   */
  public static hslToRgb(h: number, s: number, l: number): { r: number, g: number, b: number } {
    h = h % 360;
    s = Math.max(0, Math.min(100, s)) / 100;
    l = Math.max(0, Math.min(100, l)) / 100;

    if (s === 0) {
      // 灰色
      const v = Math.round(l * 255);
      return {r: v, g: v, b: v};
    }

    const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const p = 2 * l - q;
    const hue = h / 360;

    const rt = hue + 1 / 3;
    const gt = hue;
    const bt = hue - 1 / 3;

    const hueToRgb = (t: number): number => {
      if (t < 0) t += 1;
      if (t > 1) t -= 1;

      if (t < 1 / 6) return p + (q - p) * 6 * t;
      if (t < 1 / 2) return q;
      if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
      return p;
    };

    return {
      r: Math.round(hueToRgb(rt) * 255),
      g: Math.round(hueToRgb(gt) * 255),
      b: Math.round(hueToRgb(bt) * 255)
    };
  }

  /**
   * 调整颜色亮度
   * @param color 颜色字符串 (十六进制格式, 例如: #FF0000)
   * @param level 亮度调整等级, 正数变亮, 负数变暗, 取值范围 -1.0 到 1.0
   * @returns 调整后的颜色字符串 (十六进制格式)
   * @example
   * ColorUtil.adjustBrightness('#ff0000', -0.5) // 返回 '#800000' (变暗50%)
   * ColorUtil.adjustBrightness('#ff0000', 0.5)  // 返回 '#ff8080' (变亮50%)
   */
  public static adjustBrightness(color: string, level: number): string {
    // 校验level值范围
    level = Math.max(-1.0, Math.min(1.0, level));

    // 转换颜色到RGB格式
    const rgb = this.hexToRgb(color);
    if (!rgb) {
      return color; // 如果无法解析颜色, 返回原始颜色
    }

    // 根据level调整亮度
    const factor = level < 0 ? (1 + level) : (1 - level);
    const adjust = level < 0 ? 0 : 255;

    const r = Math.round(rgb.r * factor + adjust * (1 - factor));
    const g = Math.round(rgb.g * factor + adjust * (1 - factor));
    const b = Math.round(rgb.b * factor + adjust * (1 - factor));

    // 转换回十六进制格式
    return this.rgbToHex(r, g, b);
  }

  /**
   * 调整颜色饱和度
   * @param color 颜色字符串 (十六进制格式)
   * @param amount 饱和度调整量, 正数增加饱和度, 负数减少饱和度, 取值范围 -100 到 100
   * @returns 调整后的颜色字符串 (十六进制格式)
   * @example
   * ColorUtil.adjustSaturation('#ff0000', -50) // 返回 '#bf4040' (降低50%饱和度)
   * ColorUtil.adjustSaturation('#808080', 100) // 返回 '#808080' (灰色无法增加饱和度)
   */
  public static adjustSaturation(color: string, amount: number): string {
    const rgb = this.hexToRgb(color);
    if (!rgb) {
      return color;
    }

    // 转换为HSL
    const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);

    // 调整饱和度
    hsl.s = Math.max(0, Math.min(100, hsl.s + amount));

    // 转换回RGB
    const newRgb = this.hslToRgb(hsl.h, hsl.s, hsl.l);

    // 转换为十六进制
    return this.rgbToHex(newRgb.r, newRgb.g, newRgb.b);
  }

  /**
   * 生成颜色的不同亮暗等级变体
   * @param baseColor 基础颜色 (十六进制格式)
   * @param levels 亮暗等级数组, 每个元素值范围 -1.0 到 1.0
   * @returns 包含不同亮暗等级颜色的对象, 键名为level值
   * @example
   * ColorUtil.generateColorVariants('#ff0000', [-0.5, 0, 0.5])
   * // 返回 { '-0.5': '#800000', '0': '#ff0000', '0.5': '#ff8080' }
   */
  public static generateColorVariants(baseColor: string, levels: number[]): Record<number, string> {
    const result: Record<number, string> = {};

    for (const level of levels) {
      result[level] = this.adjustBrightness(baseColor, level);
    }

    return result;
  }

  /**
   * 生成颜色的亮暗系列
   * @param baseColor 基础颜色 (十六进制格式)
   * @param steps 步数 (生成多少个颜色变体)
   * @param darkToLight 是否从暗到亮排序, 默认为true
   * @returns 颜色数组
   * @example
   * ColorUtil.generateColorSeries('#ff0000', 5)
   * // 返回 ['#000000', '#800000', '#ff0000', '#ff8080', '#ffffff']
   */
  public static generateColorSeries(baseColor: string, steps: number, darkToLight: boolean = true): string[] {
    if (steps < 2) return [baseColor];

    const results: string[] = [];
    const range = 2.0; // 总范围为-1.0到1.0, 共2.0
    const step = range / (steps - 1);

    for (let i = 0; i < steps; i++) {
      // 计算当前亮暗等级, 从-1.0到1.0
      const level = darkToLight ? -1.0 + i * step : 1.0 - i * step;
      results.push(this.adjustBrightness(baseColor, level));
    }

    return results;
  }

  /**
   * 获取颜色系列
   * @param baseColor 基础颜色 (十六进制格式, 例如: #FF0000)
   * @returns 包含不同用途颜色的颜色系列
   * @example
   * ColorUtil.getColorSeries('#ff0000')
   * // 返回一个包含各种颜色变体的ColorSeries对象
   */
  public static getColorSeries(baseColor: string): ColorSeries {
    // 确保基础颜色有效
    const rgb = this.hexToRgb(baseColor);
    if (!rgb) {
      // 默认使用灰色
      baseColor = '#808080';
    }

    // 创建不同亮度和饱和度的变体
    const lighterColor = this.adjustBrightness(baseColor, 0.2); // 稍亮
    const muchLighterColor = this.adjustBrightness(baseColor, 0.6); // 更亮
    const darkerColor = this.adjustBrightness(baseColor, -0.2); // 稍暗
    const muchDarkerColor = this.adjustBrightness(baseColor, -0.4); // 更暗

    // 降低饱和度的变体
    const desaturated = this.adjustSaturation(baseColor, -30);
    const moreDesaturated = this.adjustSaturation(baseColor, -60);

    return {
      color: baseColor,
      regularColor: baseColor,
      secondaryColor: desaturated,
      placeholderColor: this.adjustBrightness(moreDesaturated, 0.3),
      disabledColor: this.adjustBrightness(moreDesaturated, 0.5),
      borderColor: darkerColor,
      darkBorderColor: muchDarkerColor,
      lightBorderColor: lighterColor,
      lightColor: muchLighterColor,
      darkColor: muchDarkerColor,
      hoverColor: lighterColor
    };
  }

  /**
   * 根据亮暗等级获取颜色系列
   * @param baseColor 基础颜色 (十六进制格式)
   * @param level 亮暗等级, 正数变亮, 负数变暗, 取值范围 -1.0 到 1.0
   * @returns 颜色系列
   * @example
   * ColorUtil.getColorSeriesWithLevel('#ff0000', -0.3) // 返回偏暗的红色系列
   */
  public static getColorSeriesWithLevel(baseColor: string, level: number): ColorSeries {
    const adjustedColor = this.adjustBrightness(baseColor, level);
    return this.getColorSeries(adjustedColor);
  }
}
